Implement forest management practices
!! Implement forest management practices !|author: <a href="mailto:giovanni.ravazzani@polimi.it">Giovanni Ravazzani</a> ! license: <a href="http://www.gnu.org/licenses/">GPL</a> ! !### History ! ! current version 1.0 - 24th January 2020 ! ! | version | date | comment | ! |----------|-------------|----------| ! | 1.0 | 24/Jan/2020 | Original code | ! !### License ! license: GNU GPL <http://www.gnu.org/licenses/> ! !### Module Description ! Routines to manage forest (silvocoltural practices) ! MODULE PlantsManagement ! ! Modules used: USE DataTypeSizes, ONLY : & ! Imported Type Definitions: short, long, float USE LogLib, ONLY: & !Imported routines: Catch USE IniLib, ONLY : & !Imported derived types: IniList, & !Imported routines: IniOpen, IniClose , & SectionIsPresent, KeyIsPresent, & IniReadInt , IniReadReal , & GetNofSubSections, IniReadString USE GridLib, ONLY: & !imported definitions: grid_integer !, & !imported routines: !NewGrid USE GridOperations, ONLY : & !imported routines: GridByIni USE GridStatistics, ONLY: & !imported routines: UniqueValues USE StringManipulation, ONLY: & !imported routines: ToString USE Chronos , ONLY: & !imported definitions: DateTime, & !imported variables: timeString, & !Imported operands: OPERATOR ( - ), & OPERATOR ( + ), & ASSIGNMENT( = ) USE Units, ONLY: & !imported parameters: year IMPLICIT NONE !global variables LOGICAL :: plants_management TYPE (grid_integer) :: management_map !global routines: PUBLIC :: SetPlantsManagement PUBLIC :: ApplyPlantsManagement PUBLIC :: SetPractice TYPE :: thinning TYPE (DateTime) :: time !when plants are cut REAL (KIND = float) :: intensity !percentage of plants to be cut !used for reforestation LOGICAL :: reforestation !true if reforestation is required INTEGER (KIND = short) :: species !species for reforestation REAL (KIND = float) :: density ! number of plants per hectar REAL (KIND = float) :: age !(years) REAL (KIND = float) :: dbh ! stem diameter at breast height (cm) REAL (KIND = float) :: height !tree height (m) REAL (KIND = float) :: stem_biomass !(t/ha) REAL (KIND = float) :: root_biomass !(t/ha) REAL (KIND = float) :: leaf_biomass !(t/ha) REAL (KIND = float) :: lai ! leaf area index (m2/m2) END TYPE thinning TYPE :: Practice INTEGER (KIND = short) :: id TYPE (Thinning), ALLOCATABLE :: cuts (:) INTEGER (KIND = short) :: current TYPE (DateTime) :: next END TYPE Practice !local declarations: TYPE (Practice), PRIVATE, ALLOCATABLE :: practices (:) PRIVATE :: GetPos !======= CONTAINS !======= !============================================================================== !| Description: ! Set variables and options to manage plants. Basically two options are ! available: ! ! 1. Regular thinning time interval and intensity. The percentage of plants ! is removed every time interval. ! 2. Specific dates when applying a given thinning intensity ! ! A different option can be specified for each stand (cell). ! SUBROUTINE SetPlantsManagement & ! (file, begin, end ) IMPLICIT NONE !arguments with intent(in): CHARACTER (LEN = *), INTENT(IN) :: file !! file to configure plants management TYPE (DateTime), INTENT (IN) :: begin !!simulation starting date TYPE (DateTime), INTENT(IN) :: end !!simulation ending date !local declarations: TYPE(IniList) :: iniDB !!store configuration info INTEGER (KIND = short) :: i, j INTEGER (KIND = short), ALLOCATABLE :: uniques (:) INTEGER (KIND = short), ALLOCATABLE :: active_practices (:) INTEGER (KIND = short) :: count_practices INTEGER (KIND = short) :: cuts !!number of cuts INTEGER (KIND = short) :: interval !!thinning interval (years) !---------------------------------------end of declarations-------------------- !load options CALL IniOpen (file, iniDB) !set management map IF ( SectionIsPresent ( 'practice-map', iniDB) ) THEN CALL GridByIni (iniDB, management_map, section = 'practice-map') ELSE CALL Catch ('error', 'PlantsManagement', 'practice-map missing in configuration file') END IF !find unique values in management_map CALL UniqueValues (management_map, uniques) !search active management practices count_practices = 0 DO i = 1, SIZE (uniques) IF ( SectionIsPresent ( ToString (uniques(i)), iniDB ) ) THEN count_practices = count_practices + 1 ELSE CALL Catch ('warning', 'PlantsManagement', 'section ' // TRIM (ToString (uniques(i)) ) // ' has no management associated' ) END IF END DO ALLOCATE ( active_practices ( count_practices) ) j = 0 DO i = 1, SIZE (uniques) IF ( SectionIsPresent ( ToString (uniques(i)), iniDB ) ) THEN j = j + 1 active_practices (j) = uniques (i) END IF END DO ALLOCATE ( practices ( (count_practices) ) ) DO i = 1, count_practices !set id practices (i) % id = active_practices (i) !check if regular interval thinning is required IF ( KeyIsPresent (key = 'thinning-interval', iniDB = iniDB, & section = ToString (active_practices(i)) ) ) THEN interval = IniReadInt ( 'thinning-interval', iniDB, section = ToString (active_practices(i)) ) !compute how many cuts to do cuts = (end - begin) / year / interval ALLOCATE ( practices (i) % cuts (cuts) ) DO j = 1, cuts !set date and time of thinning practices (i) % cuts (j) % time = begin + INT( j * interval * year) !set percentage of thinning practices (i) % cuts (j) % intensity = IniReadReal & ( 'thinning-intensity', iniDB, section = ToString (active_practices(i)) ) !detect clear-cutting and reforestation IF ( practices (i) % cuts (j) % intensity == 100. ) THEN practices (i) % cuts (j) % reforestation = .TRUE. !read parameters for reforestation practices (i) % cuts (j) % species = & IniReadInt ( 'species', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % density = & IniReadReal ( 'density', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % age = & IniReadReal ( 'age', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % dbh = & IniReadReal ( 'dbh', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % height = & IniReadReal ( 'height', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % stem_biomass = & IniReadReal ( 'stem-biomass', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % root_biomass = & IniReadReal ( 'root-biomass', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % leaf_biomass = & IniReadReal ( 'leaf-biomass', iniDB, section = ToString (active_practices(i)) ) practices (i) % cuts (j) % lai = & IniReadReal ( 'lai', iniDB, section = ToString (active_practices(i)) ) ELSE practices (i) % cuts (j) % reforestation = .FALSE. END IF END DO !set time for next cut practices (i) % next = practices (i) % cuts (1) % time practices (i) % current = 0 ELSE ! thinning at given dates cuts = GetNofSubSections ( ini = iniDB, sectionname = ToString (active_practices(i)) ) ALLOCATE ( practices (i) % cuts (cuts) ) DO j = 1, cuts !set date and time of thinning timeString = IniReadString & ( 'date', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) timeString (11:) = 'T00:00:00+00:00' practices (i) % cuts (j) % time = timeString !set percentage of thinning practices (i) % cuts (j) % intensity = IniReadReal & ( 'thinning-intensity', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) !detect clear-cutting and reforestation IF ( practices (i) % cuts (j) % intensity == 100. ) THEN practices (i) % cuts (j) % reforestation = .TRUE. !read parameters for reforestation practices (i) % cuts (j) % species = & IniReadInt ( 'species', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % density = & IniReadReal ( 'density', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % age = & IniReadReal ( 'age', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % dbh = & IniReadReal ( 'dbh', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % height = & IniReadReal ( 'height', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % stem_biomass = & IniReadReal ( 'stem-biomass', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % root_biomass = & IniReadReal ( 'root-biomass', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % leaf_biomass = & IniReadReal ( 'leaf-biomass', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) practices (i) % cuts (j) % lai = & IniReadReal ( 'lai', iniDB, section = ToString (active_practices(i)), subsection = 'cut' // ToString (j) ) ELSE practices (i) % cuts (j) % reforestation = .FALSE. END IF END DO !set time for next cut practices (i) % next = practices (i) % cuts (1) % time practices (i) % current = 0 END IF END DO !freememory DEALLOCATE ( uniques ) DEALLOCATE ( active_practices ) !close option file CALL IniClose (iniDB) RETURN END SUBROUTINE SetPlantsManagement !============================================================================== !| Description: ! Set variables and options to manage plants. Basically two options are ! available: ! ! 1. Regular thinning time interval and intensity. The percentage of plants ! is removed every time interval. ! ! 2. specific dates when applying a given thinning intensity ! ! A different option can be specified for each stand (cell). ! SUBROUTINE ApplyPlantsManagement & ! (time, pract, density, root, stem, leaf, total, lai, cover, age, height, dbh, stem_yield) IMPLICIT NONE !arguments with intent(in): TYPE (DateTime), INTENT(IN) :: time !arguments with intent(inout) :: TYPE (Practice) , INTENT (INOUT) :: pract REAL (KIND = float), INTENT (INOUT) :: density REAL (KIND = float), INTENT (INOUT) :: root REAL (KIND = float), INTENT (INOUT) :: stem REAL (KIND = float), INTENT (INOUT) :: leaf REAL (KIND = float), INTENT (INOUT) :: total REAL (KIND = float), INTENT (INOUT) :: lai REAL (KIND = float), INTENT (INOUT) :: cover REAL (KIND = float), INTENT (INOUT) :: age REAL (KIND = float), INTENT (INOUT) :: height REAL (KIND = float), INTENT (INOUT) :: dbh !arguments with intent(out) :: REAL (KIND = float), INTENT (OUT) :: stem_yield !local declarations: INTEGER (KIND = short) :: pos INTEGER (KIND = short) :: ncut REAL (KIND = float) :: stem_before !------------------------end of declarations----------------------------------- ncut = pract % current stem_before = stem IF ( pract % cuts (ncut) % reforestation) THEN stem_yield = stem_before density = pract % cuts (ncut) % density root = pract % cuts (ncut) % root_biomass stem = pract % cuts (ncut) % stem_biomass leaf = pract % cuts (ncut) % leaf_biomass total = root + stem + leaf lai = pract % cuts (ncut) % lai age = pract % cuts (ncut) % age height = pract % cuts (ncut) % height dbh = pract % cuts (ncut) % dbh ! density = 700 # number of plants per hectar !age = 5 #(years) !dbh = 8. # # stem diameter at breast height (cm) !height = 3. # #tree height (m) !stem-biomass = 200. #(t/ha) !root-biomass = 64. #(t/ha) !leaf-biomass = 15. #(t/ha) !lai = 2. #leaf area index (m2/m2) ELSE !no clear cutting, update biomass density = density * ( 1. - pract % cuts (ncut) % intensity / 100. ) root = root * ( 1. - pract % cuts (ncut) % intensity / 100. ) stem = stem * ( 1. - pract % cuts (ncut) % intensity / 100. ) leaf = leaf * ( 1. - pract % cuts (ncut) % intensity / 100. ) total = total * ( 1. - pract % cuts (ncut) % intensity / 100. ) lai = lai * ( 1. - pract % cuts (ncut) % intensity / 100. ) cover = cover * ( 1. - pract % cuts (ncut) % intensity / 100. ) stem_yield = stem_before - stem END IF RETURN END SUBROUTINE ApplyPlantsManagement !============================================================================== !| Description: ! return the position in practices array given practice id FUNCTION GetPos & ! (id) & ! RESULT (pos) IMPLICIT NONE !arguments with intent(in): INTEGER (KIND = long), INTENT(IN) :: id !local declarations: INTEGER (KIND = long) :: pos INTEGER (KIND = short) :: i !---------------------------------end of declarations-------------------------- pos = 0 DO i = 1, SIZE (practices) IF ( practices (i) % id == id) THEN pos = i EXIT END IF END DO RETURN END FUNCTION GetPos !============================================================================== !| Description: ! Set management practices to single plant stand ! SUBROUTINE SetPractice & ! (id, pract) IMPLICIT NONE !arguments with intent (in): INTEGER (KIND = long), INTENT(IN) :: id !arguments with intent (inout): TYPE (Practice), INTENT(INOUT) :: pract !local declarations: INTEGER (KIND = long) :: pos !------------------------------------------end of declarations----------------- pos = GetPos (id) IF (pos == 0) THEN RETURN !no prcatice to apply ELSE pract = practices (pos) END IF RETURN END SUBROUTINE SetPractice END MODULE PlantsManagement